home *** CD-ROM | disk | FTP | other *** search
- ;DOSKEY.COM for the IBM Personal Computer - 1987 by Jeff Prosise
- ;
- bios_data segment at 40h ;BIOS Data Area
- org 17h ;shift status byte
- shft_stat db ?
- org 84h
- crt_rows db ? ;number of display rows
- org 87h
- ega_info db ? ;EGA info byte
- bios_data ends
- ;
- code segment para public 'code'
- assume cs:code
- org 100h
- begin: jmp initialize
- ;
- copyright db 'Copyright 1987 Ziff-Davis Publishing Co.'
- author db 'Jeff Prosise'
- ;
- cls_text db 'CLS',13 ;text of clear screen command
- stackptr dw 0 ;primary command stack pointer
- locptr dw ? ;secondary command stack pointer
- zcount db ? ;stack pointer relative to zero
- ega_flag db 0 ;0=no EGA, 1=EGA installed
- insert_flag db 0 ;status of insert state
- foreground db 7 ;current foreground color
- background db 0 ;current background color
- dos_segment dw ? ;DOS input buffer segment
- columns db ? ;max display column number
- bufferptr db ? ;buffer index
- ;
- ftext db 4,'dir ',27 dup (0) ;command linked to F3 key
- db 5,'type ',26 dup (0) ;command linked to F4 key
- db 5,'copy ',26 dup (0) ;command linked to F5 key
- db 4,'del ',27 dup (0) ;command linked to F6 key
- db 6,'chdir ',25 dup (0) ;command linked to F7 key
- db 5,'path ',26 dup (0) ;command linked to F8 key
- db 7,'browse ',24 dup (0) ;command linked to F9 key
- db 3,'cls',255,27 dup (0) ;command linked to F10 key
- db 7,'backup ',24 dup (0) ;command linked to F11 key
- db 8,'restore ',23 dup (0) ;command linked to F12 key
- ;
- dos_int label dword
- old21h dw 2 dup (?) ;interrupt 21h vector
- old_int_16 dd 0 ; old vector
- ;
- ;------------------------------------------------------------------------------
- ;DOSINT routine intercepts calls to interrupt 21h.
- ;------------------------------------------------------------------------------
- dosint proc near
- ;
- ;See if this is a request for DOS function 0Ah.
- ;
- sti ;restore interrupts
- cmp ah,0Ah ;function 0Ah?
- je dos1 ;yes, then continue
- dos_exit: jmp dos_int ;no, then exit to DOS routine
- dos1: cmp dos_segment,0 ;has entry occurred before?
- jne dos3 ;yes, then branch
- ;
- ;Initialize command stack and record DS value if this is the first call.
- ;
- mov dos_segment,ds ;record DOS data segment
- push cx ;save CX and SI
- push si
- mov cx,20 ;initialize command stack area
- mov si,offset initialize
- dos2: mov byte ptr cs:[si],0
- add si,128
- loop dos2
- pop si ;restore registers
- pop cx
- ;
- ;See if the function call came from DOS.
- ;
- dos3: push bx ;save BX register
- mov bx,ds ;get DS in BX for compare
- cmp bx,dos_segment ;call generated from command line?
- pop bx ;clean up the stack
- jne dos_exit ;no, then exit
- ;
- ;Get a command line entry from the standard input device.
- ;
- push ax ;save all registers to be used
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- push dx ;resave buffer offset
- call input ;read an input string
- ;
- ;Copy the entry into the command stack.
- ;
- pop dx ;recover buffer offset
- mov si,dx ;point SI to input buffer
- mov al,[si+1] ;get length of input string
- or al,al ;is the length zero?
- je dos6 ;yes, then exit now
- inc si ;advance SI to count byte
- push cs ;point ES to command stack segment
- pop es
- mov di,stackptr ;get command stack pointer
- mov cl,7 ;convert it to an offset address
- shl di,cl
- add di,offset initialize
- mov cl,al ;transfer string length to CL
- inc cl ;increment to include count byte
- xor ch,ch ;byte to word in CX
- cld ;clear DF
- rep movsb ;copy string to command stack
- inc stackptr ;update pointer
- cmp stackptr,15 ;wrap around if necessary
- jne dos4
- mov stackptr,0
- dos4: mov ax,stackptr ;set LOCPTR = STACKPTR
- mov locptr,ax
- mov zcount,0 ;initialize base zero pointer
- ;
- ;See if the command just entered was CLS.
- ;
- mov si,dx ;point DS:SI to new string
- add si,2
- mov di,offset cls_text ;and ES:DI to 'CLS' text
- mov cx,4 ;four bytes to check
- dos5: lodsb ;get one byte
- and al,0DFh ;capitalize character
- scasb ;do the bytes match?
- jne dos6 ;no, then CLS wasn't entered
- loop dos5 ;yes, then check another byte
- call clear_screen ;clear the screen
- sub si,5 ;reset SI to count byte
- mov [si],0D00h ;clear string from DOS buffer
- ;
- ;Restore registers and exit.
- ;
- dos6: pop es ;restore registers and exit
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- iret
- dosint endp
- ;
- ;------------------------------------------------------------------------------
- ;INPUT reads an input string from the standard input device.
- ;------------------------------------------------------------------------------
- input proc near
- ;
- ;Record video information and initialize parameters.
- ;
- mov ah,15 ;get video page and columns
- int 10h
- dec ah ;calculate max column number
- mov columns,ah ;save it
- push ds ;point ES:DI to buffer
- pop es
- mov di,dx
- add di,2
- mov si,dx ;point DS:SI to character count
- inc si
- mov byte ptr [si],0 ;zero initial count
- mov bufferptr,1 ;set initial index value
- cld ;clear DF
- ;
- ;Wait for a keycode to appear in the keyboard buffer.
- ;
- getkey: mov ah,0Bh ;check keyboard buffer for keycode
- int 21h
- or al,al ;anything there?
- jne getchar ;yes, then go get it
- int 28h ;no, then execute interrupt 28h
- jmp getkey ;loop back for another try
- ;
- ;Read the keycode and process it if it's not an extended code.
- ;
- getchar: mov ah,8 ;read character from buffer
- int 21h
- or al,al ;is it an extended code?
- je excode ;yes, then branch
- cmp al,8 ;backspace key?
- jne getc1 ;no, then branch
- call backspace ;rub out a character
- jmp getkey ;return to loop
- getc1: cmp al,27 ;ESC key?
- jne getc2 ;no, then branch
- call clear_line ;yes, then clear input line
- mov ax,stackptr ;reset LOCPTR
- mov locptr,ax
- mov zcount,0 ;reset base zero pointer
- jmp getkey
- getc2: cmp al,13 ;ENTER key?
- je enter ;yes, then branch
- call printchar ;no, then print the character
- jmp getkey
- enter: call eol ;place cursor at end-of-line
- mov byte ptr es:[di],13 ;insert carriage return code
- mov ah,2 ;advance to next line
- mov dl,13
- int 21h
- ret
- ;
- ;Read the extended code and see if one of the keys F3 thru F12 was pressed.
- ;
- excode: mov ah,8 ;get extended code
- int 21h
- cmp al,133 ;F11?
- je fkey
- cmp al,134 ;F12?
- je fkey
- cmp al,61 ;less than F3?
- jb ex1 ;yes, then not F3-F10
- cmp al,68 ;greater tah 68?
- ja ex1 ;yes, then not F3-F10
- fkey: test al,80h ;high bit set (F11 or F12)?
- jz fkey1 ;no, then branch
- sub al,64 ;adjust extended code
- fkey1: sub al,61 ;normalize extended code
- cbw ;convert byte to word
- mov cl,5 ;multiply by 32
- shl ax,cl
- add ax,offset ftext ;calculate string address
- call write_command ;output command
- cmp al,255 ;AL 255 on return?
- je enter ;yes, then send entry to DOS
- jmp getkey ;return to input loop
- ;
- ;See if F1 or F2 (or either of the two shifted) was pressed.
- ;
- ex1: cmp al,59 ;F1?
- jne ex2
- inc foreground ;rotate foreground color forward
- cmp foreground,10h ;wrap around if necessary
- jne clear
- mov foreground,0
- jmp clear ;jump to clear screen routine
- ex2: cmp al,84 ;Shift-F1?
- jne ex3
- dec foreground ;decrement foreground color
- cmp foreground,0FFh ;wrap around if necessary
- jne clear
- mov foreground,0Fh
- jmp clear
- ex3: cmp al,60 ;F2 key?
- jne ex4
- inc background ;rotate background color forward
- cmp background,8 ;wrap around if necesaary
- jne clear
- mov background,0
- jmp clear
- ex4: cmp al,85 ;Shift-F2?
- jne ex5
- dec background ;decrement background color
- cmp background,0FFh ;wrap around if necessary
- jne clear
- mov background,7
- clear: call clear_screen ;clear screen and home cursor
- mov [si],0D00h ;clear input buffer
- ret
- ;
- ;See if either Home or End was pressed.
- ;
- ex5: cmp al,71 ;Home?
- jne ex6
- call home ;home the cursor
- mov bufferptr,1 ;reset pointers
- mov di,si
- inc di
- jmp getkey
- ex6: cmp al,79 ;End?
- jne ex7
- call eol ;move cursor to end-of-line
- jmp getkey
- ;
- ;See if either the left or right-arrow key was pressed.
- ;
- ex7: cmp al,75 ;Cursor-Left?
- jne ex8
- call move_left ;move left one space
- jmp getkey
- ex8: cmp al,77 ;Cursor-Right?
- jne ex9
- call move_right ;move right one space
- jmp getkey
- ;
- ;See if either INS or DEL was pressed.
- ;
- ex9: cmp al,82 ;INS?
- jne ex10
- xor insert_flag,1 ;toggle insert flag
- jmp getkey
- ex10: cmp al,83 ;DEL?
- jne ex11
- call delete ;delete character at cursor
- jmp getkey
- ;
- ;Output the last command in the stack if Cursor-Up was pressed.
- ;
- ex11: cmp al,72 ;Up?
- jne ex12
- cmp zcount,15 ;at upper limit of stack?
- je up_exit ;yes, then ignore keypress
- mov ax,locptr ;get current stack index
- dec ax ;move back one command
- cmp ax,0FFFFh ;wrap around if necessary
- jne up1
- mov ax,14
- up1: mov dx,ax ;save AX in DX
- mov cl,7 ;calculate address of command
- shl ax,cl
- add ax,offset initialize
- push si ;save SI
- mov si,ax ;transfer address to SI
- cmp byte ptr cs:[si],0 ;is there a valid command there?
- pop si ;restore SI
- je up_exit ;no, then ignore keypress
- mov locptr,dx ;set LOCPTR
- inc zcount ;increment base zero pointer
- call write_command ;output the command string
- up_exit: jmp getkey
- ;
- ;Output the next command in the stack if Cursor-Down was pressed.
- ;
- ex12: cmp al,80 ;Down?
- jne ex13
- cmp zcount,0 ;at head of command stack?
- je ex13 ;yes, then ignore keypress
- mov ax,locptr ;get current stack index
- inc ax ;advance one command
- cmp ax,15 ;wrap around if necessary
- jne dn1
- xor ax,ax
- dn1: mov locptr,ax ;set LOCPTR
- dec zcount ;decrement base zero pointer
- jnz dn2 ;branch if not at head of stack
- call clear_line ;clear command line
- jmp getkey ;return to input loop
- dn2: mov cl,7 ;calculate address of command
- shl ax,cl
- add ax,offset initialize
- call write_command ;output the command string
- ex13: jmp getkey
- input endp
- ;
- ;------------------------------------------------------------------------------
- ;PRINT_STRING writes an ASCII string to the command line.
- ;Entry: DS:SI - string address
- ; CX - number of characters
- ;------------------------------------------------------------------------------
- print_string proc near
- jcxz ps_exit ;exit if no characters
- mov ah,2 ;DOS function 2 - output char
- ps1: lodsb ;get a byte
- mov dl,al ;transfer it to DL
- int 21h ;output character
- loop ps1 ;loop until done
- ps_exit: ret
- print_string endp
- ;
- ;------------------------------------------------------------------------------
- ;WRITE_COMMAND outputs a command string.
- ;Entry: AX - string offset address | Exit: AL - character after string
- ;------------------------------------------------------------------------------
- write_command proc near
- push ax ;save address
- call clear_line ;clear input line
- pop ax ;retrieve string address
- push ds ;save DS and SI
- push si
- push cs ;point DS to string segment
- pop ds
- mov si,ax ;point SI to the string
- mov cl,[si] ;get string length
- xor ch,ch
- mov byte ptr es:[di-1],cl ;store string length
- inc si ;advance SI to string text
- write1: mov ah,2 ;print one character
- mov dl,[si]
- int 21h
- movsb ;transfer character to buffer
- inc bufferptr ;advance pointer
- loop write1 ;loop until done
- lodsb ;get first character after string
- pop si ;restore registers
- pop ds
- ret
- write_command endp
- ;
- ;------------------------------------------------------------------------------
- ;BACKSPACE deletes the character left of the cursor.
- ;------------------------------------------------------------------------------
- backspace proc near
- cmp bufferptr,1 ;at beginning of command line?
- je bs_exit ;yes, then ignore it
- mov cl,[si] ;get count
- sub cl,bufferptr ;calculate distance to end-of-line
- inc cl
- xor ch,ch
- push cx ;save it
- jcxz bs1 ;branch if at end-of-line
- ;
- ;Shift all characters right of the cursor in the buffer one slot left.
- ;
- push si ;save SI and DI
- push di
- mov si,di ;position them for shifts
- dec di
- rep movsb ;shift characters right of cursor
- pop di ;restore registers
- pop si
- ;
- ;Display the new string and update input parameters.
- ;
- bs1: call move_left ;move cursor left
- bs2: pop cx ;retrieve shift count
- push dx ;save cursor position
- push si ;save SI
- mov si,di ;point SI to new part of string
- call print_string ;print the new part
- mov ah,2 ;blank the last character
- mov dl,32
- int 21h
- pop si ;restore registers
- pop dx ;restore cursor address
- mov ah,2 ;reset the cursor
- int 10h
- dec byte ptr [si] ;decrement character count
- bs_exit: ret
- backspace endp
- ;
- ;------------------------------------------------------------------------------
- ;PRINTCHAR writes a new character to the input buffer and echoes it.
- ;------------------------------------------------------------------------------
- printchar proc near
- cmp insert_flag,0 ;insert state on?
- jne print3 ;yes, then branch
- ;
- ;Print a character in overstrike mode.
- ;
- mov cl,[si] ;get count
- cmp cl,bufferptr ;end-of-line?
- jae print2 ;no, then branch
- mov cl,[si-1] ;get maximum length
- sub cl,[si] ;subtract current length
- cmp cl,1 ;buffer full?
- je beep ;yes, then branch
- print1: inc byte ptr [si] ;increment count
- print2: stosb ;deposit new character
- mov ah,2 ;then print it
- mov dl,al
- int 21h
- inc bufferptr ;advance buffer pointer
- ret
- beep: mov ax,0E07h ;print ASCII 7 thru BIOS
- int 10h
- ret
- ;
- ;Print a character in insert mode.
- ;
- print3: mov cl,[si-1] ;get maximum length
- sub cl,[si] ;subtract current count
- cmp cl,1 ;buffer full?
- je beep ;yes, then branch
- mov cl,[si] ;get count
- cmp cl,bufferptr ;end-of-line?
- jb print1 ;yes, then branch
- sub cl,bufferptr ;calculate number of shifts
- inc cl
- xor ch,ch
- push cx ;save shift count
- push si ;save SI
- add di,cx ;position DI to end-of-line
- mov si,di ;position SI just before it
- dec si
- std ;set DF for now
- rep movsb ;make room for new character
- cld ;clear DF
- pop si ;restore SI
- mov es:[di],al ;deposit new character
- mov ah,3 ;get cursor position
- int 10h
- pop cx ;retrieve shift count
- inc cx ;increment it
- push dx ;save cursor position
- push si ;save SI
- mov si,di ;point SI to current location
- call print_string ;print new part of string
- pop si ;restore SI and DX
- pop dx
- mov ah,2 ;reset cursor position
- int 10h
- inc byte ptr [si] ;add to character count
- jmp move_right ;move cursor right
- printchar endp
- ;
- ;------------------------------------------------------------------------------
- ;DELETE deletes the character at the cursor.
- ;------------------------------------------------------------------------------
- delete proc near
- mov cl,[si] ;get count
- cmp cl,bufferptr ;end-of-line?
- jb del2 ;yes, then ignore keypress
- sub cl,bufferptr ;calculate number of shifts
- xor ch,ch ;byte to word in CX
- push cx ;save shift count
- jcxz del1 ;branch if no shifts
- push si ;save SI and DI
- push di
- mov si,di ;position registers for shift
- inc si
- rep movsb ;shift characters right of cursor
- pop di ;restore registers
- pop si
- del1: mov ah,3 ;get cursor position
- int 10h
- jmp bs2 ;exit through BACKSPACE routine
- del2: ret
- delete endp
- ;
- ;------------------------------------------------------------------------------
- ;MOVE_LEFT moves the cursor one character left.
- ;------------------------------------------------------------------------------
- move_left proc near
- cmp bufferptr,1 ;at beginning of line?
- je left3 ;yes, then ignore keypress
- mov ah,3 ;get cursor position
- int 10h
- or dl,dl ;column 0?
- je left1 ;yes, then branch
- dec dl ;decrement column number
- jmp left2
- left1: mov dl,columns ;position at end of previous line
- dec dh
- left2: mov ah,2 ;set new position
- int 10h
- dec di ;decrement pointers
- dec bufferptr
- left3: ret
- move_left endp
- ;
- ;------------------------------------------------------------------------------
- ;MOVE_RIGHT moves the cursor one character right.
- ;------------------------------------------------------------------------------
- move_right proc near
- mov cl,[si] ;get count
- cmp cl,bufferptr ;end-of-line?
- jb rt3 ;yes, then ignore keypress
- mov ah,3 ;get cursor position
- int 10h
- cmp dl,columns ;at end-of-line?
- je rt1 ;yes, then branch
- inc dl ;increment column number
- jmp rt2
- rt1: xor dl,dl ;beginning of next line
- inc dh
- rt2: mov ah,2 ;position cursor
- int 10h
- inc di ;advance pointers
- inc bufferptr
- rt3: ret
- move_right endp
- ;
- ;------------------------------------------------------------------------------
- ;HOME relocates the cursor to the beginning of the command line.
- ;------------------------------------------------------------------------------
- home proc near
- mov cl,bufferptr ;get position pointer
- dec cl ;calculate distance from start
- xor ch,ch
- jcxz home_exit ;exit if already there
- home1: push cx ;save count
- call move_left ;move left one space
- pop cx ;retrieve count
- loop home1 ;loop until done
- home_exit: ret
- home endp
- ;
- ;------------------------------------------------------------------------------
- ;EOL advances the cursor to the end of the command line.
- ;------------------------------------------------------------------------------
- eol proc near
- mov cl,[si] ;get count
- cmp cl,bufferptr ;already at end?
- jb eol_exit ;yes, then exit
- sub cl,bufferptr ;calculate distance from end
- inc cl
- xor ch,ch ;byte to word in CX
- eol1: push cx ;advance right CX times
- call move_right
- pop cx
- loop eol1
- eol_exit: ret
- eol endp
- ;
- ;------------------------------------------------------------------------------
- ;CLEAR_LINE clears the command line.
- ;------------------------------------------------------------------------------
- clear_line proc near
- mov cl,[si] ;get count
- xor ch,ch
- jcxz cline2 ;exit if no characters
- push cx ;save count
- call home ;home the cursor
- mov ah,3 ;get cursor position
- int 10h
- pop cx ;restore CX
- push dx ;save cursor address
- mov ah,2 ;print ASCII spaces
- mov dl,32
- cline1: int 21h
- loop cline1
- mov ah,2 ;home cursor again
- pop dx
- int 10h
- mov byte ptr [si],0 ;reset parameters
- mov bufferptr,1
- mov di,si
- inc di
- cline2: ret
- clear_line endp
-
- ;------------------------------------------------------------------------------
- ;CLEAR_SCREEN clears the display to the currently selected colors.
- ;------------------------------------------------------------------------------
- clear_screen proc near
- push ds ;save DS
- mov ax,bios_data ;point DS to BIOS Data Area
- mov ds,ax
- assume ds:bios_data
- mov dl,columns ;set number of columns
- mov dh,25 ;set number of screen rows
- cmp ega_flag,0 ;is there an EGA installed?
- je clear1 ;no, then branch
- test ega_info,8 ;is the EGA the active monitor?
- jnz clear1 ;no, then branch
- mov dh,crt_rows ;get number of screen rows
- clear1: mov bh,background ;formulate attribute for clear
- mov cl,4
- shl bh,cl
- or bh,foreground
- mov ax,0600h ;video function - scroll screen
- xor cx,cx ;designate entire screen
- int 10h ;clear the display
- mov ah,15 ;determine active video page
- int 10h
- mov ah,2 ;home the cursor
- xor dx,dx
- int 10h
- pop ds ;restore DS
- assume ds:nothing
- ret
- clear_screen endp
- ;
- ;----------------------------------------------------------------------
- ;This enhancement for Int 16 is installed only on machines that use it.
- ;----------------------------------------------------------------------
- int_16 proc far
- assume cs:code, ds:nothing, es:nothing, ss:nothing
-
- pushf ;save the flags
- sti ;allow interrupts
- cmp ah,2 ;affects only fn 0,1
- jb bios_1
- bios_0:
- popf ;restore flags
- jmp old_int_16 ;continue on
- bios_1:
- or ah,10h ;make extended fn
-
- call old_int_16 ;call old handler
- pushf ;save flags
-
- cmp al,0e0h ;If low byte isn't E0
- jne bios_2 ; continue normally
-
- or ah,ah ;If char(224)
- jz bios_2 ; continue
- xor al,al ;else make normal extended
- bios_2:
- popf ;restore these flags
- ret 2 ;discard original ones
-
- int_16 endp
-
- ;------------------------------------------------------------------------------
- ;INITIALIZE leaves DOSKEY resident in memory.
- ;------------------------------------------------------------------------------
- initialize proc near
- assume ds:code
- ;
- ;Determine whether an EGA is installed.
- ;
- mov ah,12h ;BIOS video function 12h
- mov bl,10h ;return EGA info subfunction
- int 10h ;get info
- cmp bl,10h ;did BL return unchanged?
- je init1 ;yes, then there's no EGA here
- inc ega_flag ;no, then there is an EGA
- ;
- ;Save and replace interrupt vectors.
- ;
- init1:
- mov ax,3521h ;save and replace int 21h vector
- int 21h
- mov old21h,bx
- mov old21h[2],es
- mov ah,25h
- lea dx,dosint
- int 21h
- ;
- ; Determine if BIOS supports enhanced keys.
- ;
- xor ax,ax
- mov es,ax
- assume es:nothing
- xor byte ptr es:[417h],80h
- mov ah,12h
- int 16h
- cmp al,byte ptr es:[417h]
- jne no_support
- xor byte ptr es:[417h],80h
- mov ah,12h
- int 16h
- cmp al,byte ptr es:[417h]
- jne no_support
-
- mov ax,3516h
- int 21h
- mov word ptr old_int_16,bx
- mov word ptr old_int_16[2],es
- mov ah,25h
- mov dx,offset int_16
- int 21h
- no_support:
- ;
- ;Terminate but leave interrupt handling code and buffer space resident.
- ;
- mov dx,offset initialize+1920 ;point DX to end of reserved area
- int 27h ;terminate-but-stay-resident
- initialize endp
- ;
- code ends
- end begin